/* 
 * JpaEventInterceptor.java
 * 
 * Data de criação: 30/10/2010
 * 
 * O2SOLUTIONS - SOLUÇÕES EM TECNOLOGIA DA INFORMAÇÃO. 
 *
 */
package br.com.o2solutions.core.aop.event;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * Aspectos relacionados aos eventos JPA lançados (persist, remove, update) para
 * a injeção de dependência dos objetos que utilizam os eventos JPA.
 * 
 * @author Osvaldeir
 * @since 30/10/2010
 * 
 */
@Aspect
@Component
public class JpaEventInterceptor {

	private Logger logger;

	@Autowired
	private ConfigurableListableBeanFactory beanFactory;

	@Pointcut("execution(@javax.persistence.PostPersist * *(..))")
	public void postPersist() {
	}

	@Pointcut("execution(@javax.persistence.PrePersist * *(..))")
	public void prePersist() {
	}

	@Pointcut("execution(@javax.persistence.PostRemove * *(..))")
	public void postRemove() {
	}

	@Pointcut("execution(@javax.persistence.PreRemove * *(..))")
	public void preRemove() {
	}

	@Pointcut("execution(@javax.persistence.PreUpdate * *(..))")
	public void preUpdate() {
	}

	@Pointcut("execution(@javax.persistence.PostUpdate * *(..))")
	public void postUpdate() {
	}

	@Pointcut("execution(@javax.persistence.PostLoad * *(..))")
	public void postLoad() {
	}

	/**
	 * Realiza a injeção de dependência sobre os objetos interceptados
	 * 
	 * @param pjp
	 *            Ponto de junção
	 * @throws Exception
	 *             Caso alguma falha aconteça.
	 */
	@Around("postPersist() || prePersist() || postRemove() || preRemove() || preUpdate() || postUpdate() || postLoad()")
	public Object doInjection(ProceedingJoinPoint pjp) throws Throwable {
		final Class<? extends Object> targetClass = pjp.getTarget().getClass();
		logger = LoggerFactory.getLogger(targetClass);
		logger.info("Interceptando o Listener de Eventos JPA => "+targetClass);
		Object target = pjp.getTarget();
		logger = LoggerFactory.getLogger(target.getClass());
		AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
		processor.setBeanFactory(beanFactory);
		processor.processInjection(target);
		logger.info("Injeção realizada no objeto ".concat(target.getClass()
				.getName()));
		return pjp.proceed();
	}

	/**
	 * Atribui o beanfactory.
	 * 
	 * @param beanFactory
	 */
	@Autowired
	public void setBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

}
